#include #include // Initialize the LCD, set the address to 0x27 or 0x3F depending on your module LiquidCrystal_I2C lcd(0x27, 16, 2); // 16 columns, 2 rows // Pin setup int ledPins[] = {4, 5, 6, 7, 8, 9, 10, 11, 12, 13}; // Pins for the 8 LEDs int buttonPin = 2; // Pin for the button int buzzerPin = 3; // Pin for the piezo buzzer int middleLED = 5; // The middle LED position (adjust if needed) int direction = 1; // Initial direction (1 = forward, -1 = backward) int currentLED = 0; // Start at the first LED int level = 1; // Start at level 1 int delayTime = 300; // Initial delay time for LED movement (in ms) int score = 0; // Player score int levelTime = 10; // Time allowed for each level (in seconds) unsigned long startTime; // Time when the level starts unsigned long lastMoveTime = 0; // Time when the LEDs last moved unsigned long lastToneTime = 0; // Time to control the duration of the tone unsigned long buttonDebounceTime = 0; // For button debouncing unsigned long debounceDelay = 50; // Debounce delay in milliseconds int lastRemainingTime = -1; // To track the last displayed time int lastLevel = -1; // To track the last displayed level int lastScore = -1; // To track the last displayed score bool buttonPressed = false; bool tonePlaying = false; // Flag to indicate whether the tone is currently playing bool gameEnded = false; // Flag to indicate the end of the game // Function to play a tone non-blocking void startTone(int frequency) { tone(buzzerPin, frequency); // Start playing the tone tonePlaying = true; // Set tone playing flag lastToneTime = millis(); // Record when the tone started } void stopTone() { noTone(buzzerPin); // Stop playing the tone tonePlaying = false; // Reset tone playing flag } void setup() { // Initialize the LCD lcd.init(); lcd.backlight(); lcd.clear(); lcd.setCursor(0, 0); lcd.print("HUNTER Game"); delay(2000); // Display the welcome message for 2 seconds // Pin configurations for (int i = 0; i < 10; i++) { pinMode(ledPins[i], OUTPUT); // Set all LED pins as outputs } pinMode(buttonPin, INPUT_PULLUP); // Set button pin as input with pullup pinMode(buzzerPin, OUTPUT); // Set buzzer pin as output Serial.begin(9600); // Start serial for debugging Serial.println("Welcome to the Knight Rider Hunter Game!"); lcd.clear(); displayStatus(); // Display the initial level, score, and time startTime = millis(); // Record when the level starts lastMoveTime = millis(); // Initialize the last move time } void loop() { // If the game has ended, stop further operations if (gameEnded) { return; } // Check if the timer has expired unsigned long elapsedTime = (millis() - startTime) / 1000; int remainingTime = levelTime - elapsedTime; // If time has run out, end the game if (remainingTime <= 0) { endGame(); // Call the function to end the game return; // Stop further execution } // Handle LED movement (non-blocking using millis) if (millis() - lastMoveTime >= delayTime) { moveLED(); lastMoveTime = millis(); // Reset the last move time startTone(1000); // Start playing the 1000Hz tone when moving LED } // Stop the tone after 50ms if (tonePlaying && millis() - lastToneTime >= 50) { stopTone(); // Stop the tone after 50ms } // Check if the button is pressed (with debouncing) int buttonState = digitalRead(buttonPin); if (buttonState == LOW && millis() - buttonDebounceTime > debounceDelay) { buttonDebounceTime = millis(); // Reset debounce timer if (currentLED == middleLED) { Serial.println("You win this level!"); score++; // Increase score for a successful hit startTone(2000); // Play victory tone delay(500); // Play for 500ms stopTone(); levelUp(); // Go to the next level } else { Serial.println("Missed! Try again."); startTone(500); // Play fail sound delay(300); // Play for 300ms stopTone(); } delay(500); // Short pause after button press } // Update LCD with the remaining time and score only if there's a change if (remainingTime != lastRemainingTime || level != lastLevel || score != lastScore) { displayStatus(); lastRemainingTime = remainingTime; lastLevel = level; lastScore = score; } } // Function to move the LEDs void moveLED() { // Turn off all LEDs for (int i = 0; i < 10; i++) { digitalWrite(ledPins[i], LOW); } // Light up the current LED digitalWrite(ledPins[currentLED], HIGH); // Move the LED in the current direction currentLED += direction; // Reverse direction if we reach the end of the LED array if (currentLED == 9 || currentLED == 0) { direction = -direction; } } // Function to advance to the next level void levelUp() { level++; // Increase the level delayTime -= 30; // Decrease delay time to make LEDs move faster // Ensure delayTime doesn't go below a certain threshold (e.g., 50 ms) if (delayTime < 50) { delayTime = 50; } Serial.print("Level Up! Now at Level: "); Serial.println(level); Serial.print("New LED Speed (ms): "); Serial.println(delayTime); // Play level-up sound startTone(1500); // Play a tone at 1.5kHz delay(300); // Play for 300ms stopTone(); delay(1000); // Give a 1-second pause before starting the next level // Reset the timer for the next level startTime = millis(); } // Function to display the current level, score, and remaining time void displayStatus() { // Calculate the remaining time in seconds unsigned long elapsedTime = (millis() - startTime) / 1000; // Convert to seconds int remainingTime = levelTime - elapsedTime; // Calculate the remaining time // Ensure the remaining time does not go negative if (remainingTime < 0) { remainingTime = 0; } lcd.setCursor(0, 0); lcd.print("Lvl:"); lcd.print(level); lcd.setCursor(6, 0); lcd.print("Time:"); lcd.print(remainingTime); // Correctly print the remaining time in seconds // Clear any leftover characters by overwriting with a space if (remainingTime < 10) { lcd.print(" "); // Overwrite the extra digit when remainingTime is a single digit } lcd.setCursor(0, 1); lcd.print("Score:"); lcd.print(score); } // Function to end the game when the timer runs out void endGame() { gameEnded = true; // Set the flag to end the game // Turn off all LEDs for (int i = 0; i < 8; i++) { digitalWrite(ledPins[i], LOW); } // Display "End Game" and the final score on the LCD lcd.clear(); lcd.setCursor(0, 0); lcd.print("End Game"); lcd.setCursor(0, 1); lcd.print("Score:"); lcd.print(score); // Play a sound to indicate the game has ended startTone(300); // Play a low tone delay(1000); // Play for 1 second stopTone(); // Wait for 3 seconds before starting a new game delay(3000); // Restart the game resetGame(); } // Function to reset the game and start a new one void resetGame() { gameEnded = false; // Reset the game end flag score = 0; // Reset the score to 0 level = 1; // Reset the level to 1 delayTime = 300; // Reset the delay time for LED movement startTime = millis(); // Reset the timer // Clear the LCD and display the initial status lcd.clear(); displayStatus(); Serial.println("New game started!"); // Restart the LED movement immediately lastMoveTime = millis(); }